package mycompany.controller;

import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import mycompany.model.UserBaseModel;
import mycompany.model.chat.PrivateChatModel;
import mycompany.model.message.MessageBaseModel;
import mycompany.service.ChatService;
import mycompany.service.UserService;
import org.apache.log4j.Logger;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

/**
 *
 * @author Volodymyr Lavrynovych <volodya.lavrynovych@gmail.com>
 */
@Controller
@RequestMapping("/chats/private")
public class PrivateChatController {
    
    private static final Logger log = Logger.getLogger(PrivateChatController.class);
    private ChatService chatService = ChatService.getInstance();
    private UserService userService = UserService.getInstance();
    
    @RequestMapping("/userCount")
    public @ResponseBody String getUsersCount(String userId) {
        return "Users: "+userService.getUsersCount()+" Chats: "+chatService.getActiveChatsCount();
    }
    
    @RequestMapping("/create")
    public @ResponseBody String createChat(HttpSession session) {
        UserBaseModel user = getUser(session);
        return chatService.createPrivateChat(user)+"";
    }
    
    @RequestMapping(value = "/{chatId}/close", method = RequestMethod.POST)
    public void close(@PathVariable(value = "chatId") String chatId, HttpSession session) {
        chatService.getChatById(chatId).setActivityStatus(getUser(session), false);
    }
    
    @RequestMapping(value = "/{chatId}/addMessage", method = RequestMethod.POST)
    public @ResponseBody String addMessage(@PathVariable(value = "chatId") String chatId, String text, HttpSession session) {
        try{
            chatService.getChatById(chatId).addMessage(getUser(session), text);
        } catch(Exception ex){
            return Boolean.FALSE.toString();
        }
        return Boolean.TRUE.toString();
    }
    
    @RequestMapping(value = "/{chatId}/getMessages", method = RequestMethod.POST)
    @ResponseBody
    public void getMessages(@PathVariable(value = "chatId") String chatId, long lastMessageId, HttpServletResponse response) {
        try {
            List<MessageBaseModel> messages = chatService.getChatById(chatId).getNewMessages(lastMessageId);
            
            MappingJacksonHttpMessageConverter jsonConverter = new MappingJacksonHttpMessageConverter();
            MediaType jsonMimeType = MediaType.APPLICATION_JSON;
            if (jsonConverter.canWrite(messages.getClass(), jsonMimeType)) {
                jsonConverter.write(messages, jsonMimeType, new ServletServerHttpResponse(response));
            }
        } catch (Exception ex) {
            log.debug(ex.getMessage());
        }
    }
    
    @RequestMapping(value = "/{chatId}/removeMessage", method = RequestMethod.POST)
    @ResponseBody
    public String removeMessage(@PathVariable(value = "chatId") String chatId, long id, HttpSession session, HttpServletResponse response) {
        try {
            PrivateChatModel chat = (PrivateChatModel)chatService.getChatById(chatId);
            return chat.removeMessage(getUser(session), id) ? Boolean.TRUE.toString() : Boolean.FALSE.toString();
        } catch (Exception ex) {
            log.debug(ex.getMessage());
            return Boolean.FALSE.toString();
        }
    }
    
    @RequestMapping(value = "/{chatId}/setPassword", method = RequestMethod.POST)
    @ResponseBody
    public String setPassword(@PathVariable(value = "chatId") String chatId, String oldPassword, String newPassword, HttpSession session) {
        try {
            PrivateChatModel chat = (PrivateChatModel)chatService.getChatById(chatId);
            return chat.setPassword(getUser(session), oldPassword, newPassword) +"";
        } catch (Exception ex) {
            log.debug(ex.getMessage());
            return Boolean.FALSE.toString();
        }
    }
    
    @RequestMapping(value = "/{chatId}/hasPassword", method = RequestMethod.POST)
    @ResponseBody
    public String hasPassword(@PathVariable(value = "chatId") String chatId, HttpSession session) {
        try {
            log.info("hasPassword -------------");
            PrivateChatModel chat = (PrivateChatModel)chatService.getChatById(chatId);
            log.info(chat.isValidPassword(""));
            return (!chat.isValidPassword("")) +"";
        } catch (Exception ex) {
            log.debug(ex.getMessage());
            return Boolean.FALSE.toString();
        }
    }
    
    @RequestMapping(value = "/{chatId}/getRemovedMessages", method = RequestMethod.POST)
    @ResponseBody
    public void getRemovedMessages(@PathVariable(value = "chatId") String chatId, HttpSession session, HttpServletResponse response) {
        try {
            PrivateChatModel chat = (PrivateChatModel)chatService.getChatById(chatId);
            List<Long> list = chat.getRemovedMessagesIds();

            MappingJacksonHttpMessageConverter jsonConverter = new MappingJacksonHttpMessageConverter();
            MediaType jsonMimeType = MediaType.APPLICATION_JSON;
            if (jsonConverter.canWrite(list.getClass(), jsonMimeType)) {
                jsonConverter.write(list, jsonMimeType, new ServletServerHttpResponse(response));
            }
        } catch (Exception ex) {
            log.debug(ex.getMessage());
        }
    }
    
    
    @RequestMapping(value = "/{chatId}/leave", method = RequestMethod.POST)
    public @ResponseBody String leave(@PathVariable(value = "chatId") String chatId, HttpSession session) {
        try {
            return chatService.getChatById(chatId).removeUser(getUser(session))+"";
        } catch (Exception ex) {
            log.debug(ex.getMessage());
            return Boolean.FALSE.toString();
        }
    }
    
    @RequestMapping(value = "/{chatId}/status")
    public @ResponseBody String getStatus(@PathVariable(value = "chatId") String chatId) {
        try{
            return chatService.getChatById(chatId).isActive()+"";
        } catch(Exception ex){
            return Boolean.FALSE.toString();
        }
    }
    
    @RequestMapping(value = "/{chatId}/partner")
    public @ResponseBody String getPartner(@PathVariable(value = "chatId") String chatId, HttpSession session) {
        try{
            return ((PrivateChatModel)chatService.getChatById(chatId)).getPartnerName(getUser(session));
        } catch(Exception ex){
            return  "";
        }
    }
    
    @RequestMapping("/{chatId}/")
    public ModelAndView join(@PathVariable(value = "chatId") String chatId, String password, HttpSession session) {
        ModelAndView model = new ModelAndView("/chats/private");
        model.addObject("chatId", chatId);
        try{
            PrivateChatModel chat = (PrivateChatModel) chatService.getChatById(chatId);
            if(!chat.isValidPassword(password)) return model;
            
            UserBaseModel user = getUser(session);
            model.addObject("userId", user.getId());

            boolean availability = chat.addUser(user) || chat.hasUser(user);
            model.addObject("availability", availability);
            model.addObject("isOwner", chat.isOwner(user));
        } catch(Exception ex){
            model.addObject("availability", false);
            model.addObject("isOwner", false);
            model.addObject("userId", "");
        }
        return model;
    }
    
    /**
     * Method wrapper
     * @param session defines session
     * @return user model
     */
    private UserBaseModel getUser(HttpSession session){
        return userService.indentifyUser(session);
    }
}
